package com.seqb.common.utils;

import com.seqb.utils.JsonUtils;
import com.seqb.utils.PageUtils;
import com.seqb.utils.ReflectUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 * @author lilinshen
 * @title es工具类
 * @description 请填写相关描述
 * @date 2019/12/11
 */
@Component
public class ElasticsearchUtils {

    private final static String INDEX_ID = "id";
    private final static String ENDS_DO = "DO";
    private final static String INDEX_SUFFIX = "_index";
    private final static String TYPE_SUFFIX = "_type";

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 新增es的数据
     */
    public boolean save(Object object) {
        try {
            String simpleName = getSimpleName(object);
            IndexQuery indexQuery = new IndexQuery();
            Object idValue = ReflectUtils.getFieldValueByName(INDEX_ID, object);
            if (null != idValue) {
                indexQuery.setId(String.valueOf(idValue));
            }
            indexQuery.setSource(JsonUtils.beanToJson(object));
            indexQuery.setIndexName(simpleName + INDEX_SUFFIX);
            indexQuery.setType(simpleName + TYPE_SUFFIX);
            elasticsearchTemplate.index(indexQuery);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 更新es的数据
     */
    public boolean update(Object object) {
        try {
            String simpleName = getSimpleName(object);
            IndexQuery indexQuery = new IndexQuery();
            Object idValue = ReflectUtils.getFieldValueByName(INDEX_ID, object);
            if (null != idValue) {
                indexQuery.setId(String.valueOf(idValue));
            }
            indexQuery.setSource(JsonUtils.beanToJson(object));
            indexQuery.setIndexName(simpleName + INDEX_SUFFIX);
            indexQuery.setType(simpleName + TYPE_SUFFIX);
            elasticsearchTemplate.index(indexQuery);
            return true;
        } catch (Exception e) {
            return false;
        }
    }


    /**
     * 通过id，删除es的数据
     */
    public boolean deleteById(Long id, Class clazz) {
        try {
            String simpleName = getSimpleName(clazz);
            String indexName = simpleName + INDEX_SUFFIX;
            String typeName = simpleName + TYPE_SUFFIX;
            elasticsearchTemplate.delete(indexName, typeName, String.valueOf(id));
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 删除es的数据
     */
    public boolean delete(Object object) {
        try {
            DeleteQuery delete = new DeleteQuery();
            String simpleName = getSimpleName(object);
            delete.setIndex(simpleName + INDEX_SUFFIX);
            delete.setType(simpleName + TYPE_SUFFIX);
            BoolQueryBuilder queryBuilder = genQueryBuilder(object);
            delete.setQuery(queryBuilder);
            elasticsearchTemplate.delete(delete);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public PageUtils list(Map<String, Object> params, Class clazz) {
        try {
            String simpleName = getSimpleName(clazz);
            String indexName = simpleName + INDEX_SUFFIX;
            String typeName = simpleName + TYPE_SUFFIX;
            BoolQueryBuilder queryBuilder = genQueryBuilder(params, clazz);
            int pageNumber = 0;
            int pageSize = Integer.MAX_VALUE;
            if (null != params.get("pageNumber") && null != params.get("pageNumber")) {
                pageNumber = Integer.parseInt(String.valueOf(params.get("pageNumber")));
                pageSize = Integer.parseInt(String.valueOf(params.get("pageSize")));
                if (pageNumber > 0) {
                    pageNumber = pageNumber - 1;
                }
            }
            Pageable pageable = PageRequest.of(pageNumber, pageSize, new Sort(Sort.Direction.DESC, "id"));
            NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withIndices(indexName)
                    .withTypes(typeName)
                    .withQuery(queryBuilder)
                    .withPageable(pageable)
                    .build();

            AggregatedPage aggregatedPage = elasticsearchTemplate.queryForPage(searchQuery, clazz);
            List list = aggregatedPage.getContent();
            long total = aggregatedPage.getTotalElements();
            return new PageUtils(list, total);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 构造一个QueryBuilder
     */
    public static BoolQueryBuilder genQueryBuilder(Map<String, Object> params, Class clazz) {
        if (null == params || null == clazz) {
            return null;
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        try {
            Field[] declaredFields = clazz.getDeclaredFields();
            for (int i = 0; i < declaredFields.length; i++) {
                Field field = declaredFields[i];
                String fieldName = field.getName();
                Object value = params.get(fieldName);
                if (null != value && !"".equals(value)) {
                    String fileValue = String.valueOf(value);
                    if (fileValue.startsWith("%") || fileValue.endsWith("%")) {
                        fileValue = fileValue.replace("%", "");
                        fileValue = "*" + fileValue + "*";
                        queryBuilder.must(QueryBuilders.wildcardQuery(fieldName, fileValue));
                    } else {
                        queryBuilder.must(QueryBuilders.matchQuery(fieldName, fileValue));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return queryBuilder;
    }


    /**
     * 构造一个QueryBuilder
     */
    public static BoolQueryBuilder genQueryBuilder(Object object) {
        if (null == object) {
            return null;
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        try {
            Field[] declaredFields = object.getClass().getDeclaredFields();
            for (Field field : declaredFields) {
                String fieldName = field.getName();
                Object value = ReflectUtils.getFieldValueByName(fieldName, object);
                if (null != value && !"".equals(value)) {
                    String fileValue = String.valueOf(value);
                    if (fileValue.startsWith("%") || fileValue.endsWith("%")) {
                        fileValue = fileValue.replace("%", "");
                        fileValue = "*" + fileValue + "*";
                        queryBuilder.must(QueryBuilders.wildcardQuery(fieldName, fileValue));
                    } else {
                        queryBuilder.must(QueryBuilders.matchQuery(fieldName, fileValue));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return queryBuilder;
    }

    /**
     * 获取对象的简单名称
     */
    private String getSimpleName(Object object) {
        String simpleName = object.getClass().getSimpleName();
        if (simpleName.endsWith(ENDS_DO)) {
            simpleName = simpleName.substring(0, simpleName.lastIndexOf(ENDS_DO));
        }
        return simpleName.toLowerCase();
    }

    /**
     * 获取对象的简单名称
     */
    private String getSimpleName(Class clazz) {
        String simpleName = clazz.getSimpleName();
        if (simpleName.endsWith(ENDS_DO)) {
            simpleName = simpleName.substring(0, simpleName.lastIndexOf(ENDS_DO));
        }
        return simpleName.toLowerCase();
    }

}
